package model

import (
	"blog2021/configs"
	"blog2021/tools/logger"
	"blog2021/tools/util"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"

	"github.com/jinzhu/gorm"

	"github.com/PuerkitoBio/goquery"
)

const BingHost = "https://cn.bing.com"

type Bing struct {
	gorm.Model
	Title  string `gorm:"column:title"`
	Author string `gorm:"column:author"`
	Url    string `gorm:"column:url"`
	Date   string `gorm:"column:date"`
	Likes  int    `gorm:"column:likes"`
}

func GetImageName(imageUrl string) (string, error) {
	u, err := url.Parse(imageUrl)
	if err != nil {
		return "", err
	}
	names, exist := u.Query()["id"]
	if exist && len(names) > 0 {
		return names[0], nil
	}
	return "", errors.New("name not found")
}

func GetBingWallpaper() (Bing, error) {
	result := Bing{}
	resp, err := http.Get(BingHost)
	if err != nil {
		return result, err
	}
	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return result, err
	}

	wallpaperUrl := ""
	wallpaperTitle := ""
	doc.Find("body #bgImgProgLoad").Each(func(i int, s *goquery.Selection) {
		src, exist := s.Attr("data-ultra-definition-src")
		if exist {
			wallpaperUrl = BingHost + src
		}
	})

	doc.Find("body #sh_cp").Each(func(i int, s *goquery.Selection) {
		wallpaperTitle, _ = s.Attr("title")
	})

	if len(wallpaperTitle) > 0 && len(wallpaperUrl) > 0 {
		start := strings.Index(wallpaperTitle, "(")
		end := strings.LastIndex(wallpaperTitle, ")")
		if end > start && start >= 0 {
			result.Title = wallpaperTitle[0:start]
			result.Author = wallpaperTitle[start+1 : end]
		} else {
			result.Title = wallpaperTitle
		}
		result.Title = strings.Trim(result.Title, " ")
		result.Author = strings.Trim(result.Author, " ")
		result.Date = time.Now().Format("2006-01-02")
		result.Url = wallpaperUrl
		if err := WriteBing(result); err != nil {
			logger.Error(err)
		}
		return result, nil
	}
	return result, errors.New("invalid")
}

func DownloadBingWallpaper() error {
	bing, err := GetBingWallpaper()
	if err != nil {
		return err
	}
	name, err := GetImageName(bing.Url)
	if err != nil {
		return err
	}

	imageLocalPath := path.Join(configs.BingDir(), name)
	if util.PathExist(imageLocalPath) {
		logger.Info("local image found", imageLocalPath)
		return nil
	}

	imageResp, err := http.Get(bing.Url)
	if err != nil {
		return err
	}
	defer imageResp.Body.Close()

	b, err := ioutil.ReadAll(imageResp.Body)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(imageLocalPath, b, os.ModePerm)
	if err != nil {
		return err
	}

	return nil
}

func WriteBing(bing Bing) error {
	var oldBing Bing
	err := db.Where("url = ?", bing.Url).Find(&oldBing).Error
	if err == nil {
		return nil
	}
	return db.Save(&bing).Error
}

func Bing2Data(bing Bing) Bing {
	var data Bing
	data.Date = bing.Date[0:10]
	data.Url = bing.Url
	start := strings.Index(bing.Title, "(")
	end := strings.LastIndex(bing.Title, ")")
	data.Title = bing.Title[0 : start-1]
	data.Author = bing.Title[start+1 : end]
	return data
}

func GetBingPage(page int) ([]Bing, error) {
	offset := (page - 1) * MaxBingPageCount
	limit := MaxBingPageCount
	var bings []Bing
	err := db.Order("date desc").
		Limit(limit).Offset(offset).
		Find(&bings).Error
	if err != nil {
		logger.Error(err)
		return []Bing{}, err
	}
	return bings, err
}

func GetBingDate(date string) (Bing, error) {
	var bing Bing
	if err := db.Where("date = ?", date).Find(&bing).Error; err != nil {
		logger.Error(err)
	}
	return bing, nil
}

func LikesIncr(id int) error {
	return db.Exec("update bings set likes=likes+1 where id=?", id).Error
}
